package nl.ru.rd.facedetection.nnbfd;

/**
 * A histrogram equalizer to be used in the preprocessor.
 * 
 * @author Christiaan Thijssen s0814970
 * @author Kevin Reintjes s0814954
 * @author Wouter Geraedts (s0814857 - wgeraedts) PGP 66AA5935
 */
public class HistogramEqualizer
{
	final static short Levels = 256;

	/**
	 * Equalize the matrix using histogram equalization.
	 * 
	 * @param matrix
	 *            The matrix to be equalized
	 */
	public void equalize(Matrix matrix)
	{
		int[] histogram = new int[Levels];
		for(int i = 0; i < Levels; i++)
			histogram[i] = 0;

		int height = matrix.getHeight();
		int width = matrix.getWidth();

		for(int y = 0; y < height; y++)
			for(int x = 0; x < width; x++)
				histogram[matrix.getValue(x, y)]++;

		cummulate(histogram);

		int mincdf = histogram[0];

		modifyImageMatrix(matrix, histogram, mincdf);
	}

	/**
	 * Calculates the cummalative values of the histogram
	 * 
	 * @param histogram
	 *            The histogram to be cummulated
	 */
	private void cummulate(int[] histogram)
	{
		for(int i = 1; i < Levels; i++)
			histogram[i] = histogram[i] + histogram[i - 1];
	}

	/**
	 * Changes the matrix according the cummulative values of the histogram
	 * 
	 * @param matrix
	 *            The matrix to be changed
	 * @param histogram
	 *            The cummulative values of the histogram
	 * @param mincdf
	 *            The minimum value of the cummulative histogram
	 */
	private void modifyImageMatrix(Matrix matrix, int[] histogram, int mincdf)
	{
		int height = matrix.getHeight();
		int width = matrix.getWidth();
		int normalizedDimension = height * width - mincdf;

		for(int y = 0; y < height; y++)
			for(int x = 0; x < width; x++)
			{
				int normalizedCummulativeValue = histogram[matrix.getValue(x, y)] - mincdf;

				double newLevel = (double) normalizedCummulativeValue / (double) normalizedDimension;

				matrix.setValue(x, y, (short) Math.round(newLevel * (Levels - 1)));
			}
	}
}